
/**
 * \file ring_buffer.c
 * \brief 简易环形缓冲的实现
 * \author netube_99\netube@163.com
 * \date 2022.08.20
 * \version v0.4.0
*/

#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "ring_buffer.h"

#define rb_log(fmt, ...) printf("[RB][%d]%s:"fmt"\r\n", __LINE__, __func__, ##__VA_ARGS__);

/**
 * \brief 初始化新缓冲区
 * \param[out] rb_handle: 待初始化的缓冲区结构体句柄
 * \param[in] buffer_addr: 外部定义的缓冲区数组，类型必须为 uint8_t
 * \param[in] buffer_size: 外部定义的缓冲区数组空间
 * \return 返回缓冲区初始化的结果
 *      \arg RING_BUFFER_SUCCESS: 初始化成功
 *      \arg RING_BUFFER_ERROR: 初始化失败
*/
uint8_t RB_Init(ring_buffer *rb_handle, uint8_t *buffer_addr ,uint32_t buffer_size)
{
    //缓冲区数组空间必须大于2且小于数据类型最大值
    if(buffer_size < 2 || buffer_size == 0xFFFFFFFF)
        return RING_BUFFER_ERROR ; //初始化失败
    rb_handle->head = 0 ; //复位头指针
    rb_handle->tail = 0 ; //复位尾指针
    rb_handle->Length = 0 ; //复位已存储数据长度
    rb_handle->array_addr = buffer_addr ; //缓冲区储存数组基地址
    rb_handle->max_Length = buffer_size ; //缓冲区最大可储存数据量
    return RING_BUFFER_SUCCESS ; //缓冲区初始化成功
}

/**
 * \brief 从头指针开始删除指定长度的数据
 * \param[out] rb_handle: 缓冲区结构体句柄
 * \param[in] Length: 要删除的长度
 * \return 返回删除指定长度数据结果
 *      \arg RING_BUFFER_SUCCESS: 删除成功
 *      \arg RING_BUFFER_ERROR: 删除失败
*/
uint8_t RB_Delete(ring_buffer *rb_handle, uint32_t Length)
{
    if(rb_handle->Length < Length)
        return RING_BUFFER_ERROR ;//已储存的数据量小于需删除的数据量
    else
    {
        if((rb_handle->head + Length) >= rb_handle->max_Length)
            rb_handle->head = Length - (rb_handle->max_Length - rb_handle->head);
        else
            rb_handle->head += Length ;    //头指针向前推进，抛弃数据
        rb_handle->Length -= Length ;      //重新记录有效数据长度
        return RING_BUFFER_SUCCESS ;//已储存的数据量小于需删除的数据量
    }
}

/**
 * \brief 向缓冲区尾部写一个字节
 * \param[out] rb_handle: 缓冲区结构体句柄
 * \param[in] data: 要写入的字节
 * \return 返回缓冲区写字节的结果
 *      \arg RING_BUFFER_SUCCESS: 写入成功
 *      \arg RING_BUFFER_ERROR: 写入失败
*/
uint8_t RB_Write_Byte(ring_buffer *rb_handle, uint8_t data)
{
    //缓冲区数组已满，产生覆盖错误
    if(rb_handle->Length == (rb_handle->max_Length))
        return RING_BUFFER_ERROR ;
    else
    {
        *(rb_handle->array_addr + rb_handle->tail) = data;//基地址+偏移量，存放数据
        rb_handle->Length ++ ;//数据量计数+1
        rb_handle->tail ++ ;//尾指针后移
    }
    //如果尾指针超越了数组末尾，尾指针指向缓冲区数组开头，形成闭环
    if(rb_handle->tail > (rb_handle->max_Length - 1))
        rb_handle->tail = 0 ;
  return RING_BUFFER_SUCCESS ;
}

/**
 * \brief 向缓冲区尾部写4个字节
 * \param[out] rb_handle: 缓冲区结构体句柄
 * \param[in] data: 要写入的字节
 * \return 返回缓冲区写字节的结果
 *      \arg RING_BUFFER_SUCCESS: 写入成功
 *      \arg RING_BUFFER_ERROR: 写入失败
*/
uint8_t RB_Write_4Byte(ring_buffer *rb_handle, uint32_t t_data)
{
    //缓冲区数组已满，产生覆盖错误
    if(rb_handle->Length == (rb_handle->max_Length))
        return RING_BUFFER_ERROR ;
    else
    {
        rb_log("t_data = %08x", t_data);
        rb_log("rb_handle->array_addr = %d", rb_handle->array_addr);
        rb_log("rb_handle->tail = %d", rb_handle->tail);
        memcpy(rb_handle->array_addr + rb_handle->tail, &t_data, sizeof(uint32_t));//基地址+偏移量，存放数据
        rb_handle->Length += sizeof(uint32_t) ;//数据量计数+1
        rb_handle->tail += sizeof(uint32_t) ;//尾指针后移
    }

    //如果尾指针超越了数组末尾，尾指针指向缓冲区数组开头，形成闭环
    rb_log("rb_handle->max_Length = %d", rb_handle->max_Length);
    rb_log("rb_handle->tail = %d", rb_handle->tail);
    if(rb_handle->tail > (rb_handle->max_Length - 4))
        rb_handle->tail = 0 ;
  return RING_BUFFER_SUCCESS ;
}

/**
 * \brief 从缓冲区头指针读取一个字节
 * \param[out] rb_handle: 缓冲区结构体句柄
 * \param[out] output_addr: 读取的字节保存地址
 * \return 返回读取状态
 *      \arg RING_BUFFER_SUCCESS: 读取成功
 *      \arg RING_BUFFER_ERROR: 读取失败
*/
uint8_t RB_Read_4Byte(ring_buffer *rb_handle, uint32_t *output_data)
{
    if (rb_handle->Length != 0)//有数据未读出
    {
        memcpy(output_data, rb_handle->array_addr + rb_handle->head, sizeof(uint32_t));
        rb_handle->head += sizeof(uint32_t) ;
        rb_handle->Length -= sizeof(uint32_t);//数据量计数-1

        rb_log("*output_data = %x", *output_data);

        //如果头指针超越了数组末尾，头指针指向数组开头，形成闭环
        if(rb_handle->head > (rb_handle->max_Length - sizeof(uint32_t)))
            rb_handle->head = 0 ;
        return RING_BUFFER_SUCCESS ;
    }
    return RING_BUFFER_ERROR ;
}

/**
 * \brief 从缓冲区头指针读取一个字节
 * \param[out] rb_handle: 缓冲区结构体句柄
 * \param[out] output_addr: 读取的字节保存地址
 * \return 返回读取状态
 *      \arg RING_BUFFER_SUCCESS: 读取成功
 *      \arg RING_BUFFER_ERROR: 读取失败
*/
uint8_t RB_Read_Byte(ring_buffer *rb_handle, uint8_t *output_addr)
{
    if (rb_handle->Length != 0)//有数据未读出
    {
        *output_addr = *(rb_handle->array_addr + rb_handle->head);//读取数据
        rb_handle->head ++ ;
        rb_handle->Length -- ;//数据量计数-1
        //如果头指针超越了数组末尾，头指针指向数组开头，形成闭环
        if(rb_handle->head > (rb_handle->max_Length - 1))
            rb_handle->head = 0 ;
        return RING_BUFFER_SUCCESS ;
    }
    return RING_BUFFER_ERROR ;
}

/**
 * \brief 向缓冲区尾部写指定长度的数据
 * \param[out] rb_handle: 缓冲区结构体句柄
 * \param[out] input_addr: 待写入数据的基地址
 * \param[in] write_Length: 要写入的字节数
 * \return 返回缓冲区尾部写指定长度字节的结果
 *      \arg RING_BUFFER_SUCCESS: 写入成功
 *      \arg RING_BUFFER_ERROR: 写入失败
*/
uint8_t RB_Write_String(ring_buffer *rb_handle, const uint8_t *input_addr, uint32_t write_Length)
{
    //如果不够存储空间存放新数据,返回错误
    if((rb_handle->Length + write_Length) > (rb_handle->max_Length))
        return RING_BUFFER_ERROR ;
    else
    {
        //设置两次写入长度
        uint32_t write_size_a, write_size_b ;
        //如果顺序可用长度小于需写入的长度，需要将数据拆成两次分别写入
        if((rb_handle->max_Length - rb_handle->tail) < write_Length)
        {
            write_size_a = rb_handle->max_Length - rb_handle->tail ;//从尾指针开始写到储存数组末尾
            write_size_b = write_Length - write_size_a ;//从储存数组开头写数据
            //分别拷贝a、b段数据到储存数组中
            memcpy(rb_handle->array_addr + rb_handle->tail, input_addr, write_size_a);
            memcpy(rb_handle->array_addr, input_addr + write_size_a, write_size_b);
            rb_handle->Length += write_Length ;//记录新存储了多少数据量
            rb_handle->tail = write_size_b ;//重新定位尾指针位置
        }
        else//如果顺序可用长度大于或等于需写入的长度，则只需要写入一次
        {
            write_size_a = write_Length ;//从尾指针开始写到储存数组末尾
            memcpy(rb_handle->array_addr + rb_handle->tail, input_addr, write_size_a);
            rb_handle->Length += write_Length ;//记录新存储了多少数据量
            rb_handle->tail += write_size_a ;//重新定位尾指针位置
            if(rb_handle->tail == rb_handle->max_Length)
                rb_handle->tail = 0 ;//如果写入数据后尾指针刚好写到数组尾部，则回到开头，防止越位
        }
        return RING_BUFFER_SUCCESS ;
    }
}

/**
 * \brief 从缓冲区头部读指定长度的数据，保存到指定的地址
 * \param[out] rb_handle: 缓冲区结构体句柄
 * \param[out] output_addr: 读取的数据保存地址
 * \param[in] read_Length: 要读取的字节数
 * \return 返回缓冲区头部读指定长度字节的结果
 *      \arg RING_BUFFER_SUCCESS: 读取成功
 *      \arg RING_BUFFER_ERROR: 读取失败
*/
uint8_t RB_Read_String(ring_buffer *rb_handle, uint8_t *output_addr, uint32_t read_Length)
{
    if(read_Length > rb_handle->Length)
        return RING_BUFFER_ERROR ;
    else
    {
        uint32_t Read_size_a, Read_size_b ;
        if(read_Length > (rb_handle->max_Length - rb_handle->head))
        {
            Read_size_a = rb_handle->max_Length - rb_handle->head ;
            Read_size_b = read_Length - Read_size_a ;
            memcpy(output_addr, rb_handle->array_addr + rb_handle->head, Read_size_a);
            memcpy(output_addr + Read_size_a, rb_handle->array_addr, Read_size_b);
            rb_handle->Length -= read_Length ;//记录剩余数据量
            rb_handle->head = Read_size_b ;//重新定位头指针位置
        }
        else
        {
            Read_size_a = read_Length ;
            memcpy(output_addr, rb_handle->array_addr + rb_handle->head, Read_size_a);
            rb_handle->Length -= read_Length ;//记录剩余数据量
            rb_handle->head += Read_size_a ;//重新定位头指针位置
            if(rb_handle->head == rb_handle->max_Length)
                rb_handle->head = 0 ;//如果读取数据后头指针刚好写到数组尾部，则回到开头，防止越位
        }
        return RING_BUFFER_SUCCESS ;
    }
}

/**
 * \brief 获取缓冲区里已储存的数据长度
 * \param[in] rb_handle: 缓冲区结构体句柄
 * \return 返回缓冲区里已储存的数据长度
*/
uint32_t RB_Get_Length(ring_buffer *rb_handle)
{
    return rb_handle->Length ;
}

/**
 * \brief 获取缓冲区可用储存空间
 * \param[in] rb_handle: 缓冲区结构体句柄
 * \return 返回缓冲区可用储存空间
*/
uint32_t RB_Get_FreeSize(ring_buffer *rb_handle)
{
    return (rb_handle->max_Length - rb_handle->Length) ;
}


void RB_Destroy(ringBuffer_obj_t *rb)
{
    if(rb->info.array_addr)
        free(rb->info.array_addr);

    if(rb)
        free(rb);

}

ringBuffer_obj_t *new_ringBuffer(uint32_t buffer_size)
{
    ringBuffer_obj_t *rbObj = NULL;
    uint8_t *buffer_addr = NULL;

    do
    {
        rbObj = malloc(sizeof(ringBuffer_obj_t));
        if(rbObj == NULL) break;

        uint8_t *buffer_addr = malloc(buffer_size);
        if(buffer_addr == NULL) break;

        if(RB_Init(&rbObj->info, buffer_addr, buffer_size) != RING_BUFFER_SUCCESS)
            break;

        //功能函数初始化
        rbObj->Delete = RB_Delete;
        rbObj->Get_FreeSize = RB_Get_FreeSize;
        rbObj->Get_Length = RB_Get_Length;
        rbObj->Read_Byte = RB_Read_Byte;
        rbObj->Read_4Byte = RB_Read_4Byte;
        rbObj->Read_String = RB_Read_String;
        rbObj->Write_Byte = RB_Write_Byte;
        rbObj->Write_4Byte = RB_Write_4Byte;
        rbObj->Write_String = RB_Write_String;

        return rbObj;
    }while(0);


    if(buffer_addr)
        free(buffer_addr);
    if(rbObj)
        free(rbObj);

    return NULL;
}

//==============================================

typedef struct
{
    int a;
    int b;
}ttt_t;

#ifdef DEBUG_MAIN
void ringBuffer_test(void)
#else
void main()
#endif
{
#if 0

    ringBuffer_obj_t *rb = NULL;
    char *tdata = "12345678";
    uint16_t tlen = 0x1234;
    ringBuffer_obj_t *usart_ringBuffer = NULL;
    // 写
    if(usart_ringBuffer == NULL)
        usart_ringBuffer = new_ringBuffer(32);

    usart_ringBuffer->Write_Byte(&usart_ringBuffer->info, tlen & 0xff);
    rb_log("tlen & 0xff = %x", tlen & 0xff);
    usart_ringBuffer->Write_Byte(&usart_ringBuffer->info, (tlen >> 8) & 0xff);
    rb_log("(tlen >> 8) & 0xff = %x", (tlen >> 8) & 0xff);

    usart_ringBuffer->Write_String(&usart_ringBuffer->info, tdata, 8);

    //读
    char p_data[1024];
    uint16_t len = 0;
    uint8_t *pLen = &len;
    usart_ringBuffer->Read_Byte(&usart_ringBuffer->info, pLen);
    rb_log("*pLen = %d", *pLen);
    usart_ringBuffer->Read_Byte(&usart_ringBuffer->info, pLen+1);
    rb_log("*pLen = %d", *pLen);
    rb_log("len = %x", len);

    memset(p_data, sizeof(p_data), 0);
    usart_ringBuffer->Read_String(&usart_ringBuffer->info, p_data, 8);
    rb_log("p_data = %s", p_data);
#elif 1

    uint32_t t_data = 0;
    ringBuffer_obj_t *rb = new_ringBuffer(2*sizeof(uint32_t));
    if(rb == NULL)
        return;
    rb->Write_4Byte(&rb->info, 0x12345678);
    rb->Write_4Byte(&rb->info, 0x56781234);
    rb->Write_4Byte(&rb->info, 0x87654321);

    rb->Read_4Byte(&rb->info, &t_data);
    rb_log("t_data = %x", t_data);
    rb->Read_4Byte(&rb->info, &t_data);
    rb_log("t_data = %x", t_data);
    rb->Read_4Byte(&rb->info, &t_data);
    rb_log("t_data = %x", t_data);


#elif 1
    ringBuffer_obj_t *rb = new_ringBuffer(20);
    if(rb == NULL)
        return;
    rb->Write_String(&rb->info, "hello world", 11);
    rb->Write_Byte(&rb->info, 3);

    len = rb->Get_Length(&rb->info);
    printf("rb->len = %d\r\n", len);

    //读缓冲区
    uint8_t get[20];

    rb->Read_String(&rb->info, get, 4);

    printf("get = %s\r\n", get);
#elif 1

    ringBuffer_obj_t *rb = new_ringBuffer(sizeof(ttt_t)*2);
    if(rb == NULL)
        return;

    ttt_t t;
    t.a = 4;
    t.b = 5;
    rb->Write_String(&rb->info, &t, sizeof(ttt_t));

    t.a = 7;
    t.b = 8;
    rb->Write_String(&rb->info, &t, sizeof(ttt_t));

    t.a = 9;
    t.b = 10;
    rb->Write_String(&rb->info, &t, sizeof(ttt_t));

    rb->Read_String(&rb->info, &t, sizeof(ttt_t));
    printf("t.a = %d\r\n", t.a);
    printf("t.b = %d\r\n", t.b);

    rb->Read_String(&rb->info, &t, sizeof(ttt_t));
    printf("t.a = %d\r\n", t.a);
    printf("t.b = %d\r\n", t.b);

    rb->Read_String(&rb->info, &t, sizeof(ttt_t));
    printf("t.a = %d\r\n", t.a);
    printf("t.b = %d\r\n", t.b);
#endif

    printf("end=============");
    rb->Destroy(rb);

}

